package org.dromara.llm.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.llm.domain.SysLlmConfig;
import org.dromara.llm.llm.factory.LLMImageOcr;
import org.dromara.llm.mapper.SysLlmConfigMapper;
import org.dromara.llm.service.IAiChatService;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.util.*;

@RestController
@RequestMapping("/llm/api")
@RequiredArgsConstructor
@Slf4j
public class AIChatController {
    private final IAiChatService aiChatService;
    private final SysLlmConfigMapper configService;
    private final LLMImageOcr llmImageOcr;
    /**
     * 处理文本聊天请求。
     * 不保存数据库
     * 没有系统提示词
     *
     * @param text 需要处理的文本内容
     * @return 返回处理结果的响应对象，包含处理后的文本数据
     */
    @SaIgnore
    @PostMapping("/chatText")
    public R<String> chatText(@NotNull(message = "文本不能为空") @RequestParam("text") String text) {
        return R.ok(aiChatService.chat(text));
    }

    /**
     * 处理文本聊天请求。
     * 不保存数据库
     * 依据系统提示词
     *
     * @param text 需要处理的文本内容
     * @param templateId 依据系统提示词模板ID
     * @return 返回处理结果的响应对象，包含处理后的文本数据
     */
    @SaIgnore
    @PostMapping("/chatTextByTemplate")
    public R<String> chatTextByTemplate(@NotNull(message = "文本不能为空") @RequestParam("text") String text,
                                        @NotNull(message = "模板ID不能为空") @RequestParam("templateId") Long templateId) {
        return R.ok(aiChatService.chatByTemplate(text,templateId));
    }

    /**
     * 聊天接口
     * 流式响应
     * @param text 待处理的文本内容
     * @return  返回处理结果的响应对象，流式数据
     */
    @SaIgnore
    @PostMapping("/chatStream")
    public Flux<ChatResponse> chatStream(@NotNull(message = "文本不能为空") @RequestParam("text") String text) {
        return aiChatService.chatStream(text);
    }
    /**
     * 翻译接口
     *
     * @param text       待翻译的文本内容
     * @param sourceLang 原始文本语言类型
     * @param targetLang 目标翻译语言类型
     * @param deviceId   请求设备唯一标识
     * @return 返回封装后的翻译结果，包含在SysMessageVo对象中
     */
    @SaIgnore
    @PostMapping("/translate")
    public R<String> translate(@NotNull(message = "文本不能为空") @RequestParam("text") String text,
                                     @NotNull(message = "原语言不能为空") @RequestParam("sourceLang") String sourceLang,
                                     @RequestParam("targetLang") String targetLang,
                                     @NotNull(message = "设备ID不能为空") @RequestHeader("deviceId") String deviceId) {
        return R.ok(aiChatService.translate(text, sourceLang, targetLang, deviceId));
    }

    /**
     * 对话文本并使用系统模板生成消息
     *
     * @param text       发送消息文本内容
     * @param templateId 系统模板ID，用于指定模板样式
     * @param deviceId   设备ID，请求头中携带，用于识别设备
     * @return 返回包含翻译后消息的响应对象
     */
    @SaIgnore
    @PostMapping("/chatBySystemTemplate")
    public R<String> chatBySystemTemplate(@NotNull(message = "发送消息不能为空") @RequestParam("text") String text,
                                                     @NotNull(message = "模板ID不能为空") @RequestParam("templateId") Long templateId,
                                                     @NotNull(message = "设备ID不能为空") @RequestHeader("deviceId") String deviceId) {
        return R.ok(aiChatService.chatByTemplate(text, templateId, deviceId));
    }

    /**
     * 识别图片中的文字
     *
     * @param prompt 提示词
     * @param file 图片文件
     * @return 封装后的响应对象，包含处理后的文本数据
     */
    @SaIgnore
    @PostMapping("/chatBySystemTemplateAndInputStream")
    public R<String> chatBySystemTemplateAndInputStream(@NotNull(message = "文本不能为空") @RequestParam("prompt") String prompt,
                                                        @RequestParam("file") MultipartFile file) throws IOException {
        SysLlmConfig config = configService.selectById(2L);
        llmImageOcr.initLLMImage(config);
        return R.ok(llmImageOcr.recognizeImageText(file, prompt));
    }
}
